/*================================================================
*   Copyright (C) 2024 baichao All rights reserved.
*
*   文件名称：rwlock_starvation_test.txt.c
*   创 建 者：baichao
*   创建日期：2024年03月20日
*   描    述：创建100个线程（50个读线程和50个写线程），读线程只读取share_cnt的值，而写线程会将share_cnt的值自加。
*            由于是while循环，所以属于读写竞争非常激烈的情况。创建线程之前，主线程会持有读写锁，直到所有线程创建完毕，然后主线程解锁，开闸放水，放任100个线程激烈地竞争读写锁。
*            如果采用读者优先的策略，则会看到由于读线程源源不断地申请读锁，写锁被活活饿死，写线程根本捞不到机会执行。运行N秒之后，share_cnt仍然是0。
*            如果我们采用写者优先的策略，情况就完全相反了，自从第一个写锁请求拿到锁之后，读锁请求就再也拿不到锁了，原因是总是有写锁请求，而写锁释放的时候，总是先唤醒写锁，表现出来很强大的惯性。
*
================================================================*/

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define N_THREAD 100

static int share_cnt = 0;
static pthread_rwlock_t rwlock;

void *reader(void *param) {
  int i = (int)param;
  while (1) {
    pthread_rwlock_rdlock(&rwlock);
    fprintf(stderr, "reader-%d: the share_cnt = %d\n", i, share_cnt);
    pthread_rwlock_unlock(&rwlock);
  }
  return NULL;
}

void *writer(void *param) {
  int i = (int)param;
  while (1) {
    pthread_rwlock_wrlock(&rwlock);
    share_cnt++;
    fprintf(stderr, "writer-%d: the share_cnt = %d\n", i, share_cnt);
    pthread_rwlock_unlock(&rwlock);
    //      sleep(1);
  }
  return NULL;
}

int main() {
  pthread_t tid[N_THREAD];
  pthread_rwlockattr_t rwlock_attr;
  pthread_rwlockattr_init(&rwlock_attr);
#ifdef WRITE_FIRST
  pthread_rwlockattr_setkind_np(&rwlock_attr,
                                PTHREAD_RWLOCK_PREFER_WRITER_NP);
#endif
  pthread_rwlock_init(&rwlock, &rwlock_attr);
  int i = 0;
  int ret = 0;
  pthread_rwlock_rdlock(&rwlock);
  for (i = 0; i < N_THREAD; i++) {
    if (i % 2 == 0) {
      ret = pthread_create(&tid[i], NULL, reader, (void *)i);
    } else {
      ret = pthread_create(&tid[i], NULL, writer, (void *)i);
    }
    if (ret != 0) {
      fprintf(stderr, "create thread %d failed \n", i);
      break;
    }
  }
  pthread_rwlock_unlock(&rwlock);
  while (i-- > 0) {
    pthread_join(tid[i], NULL);
  }
  pthread_rwlockattr_destroy(&rwlock_attr);
  pthread_rwlock_destroy(&rwlock);
  return ret;
}
